#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Thanos Chain区块链适配器
通过HTTP API与Thanos Chain区块链进行交互
"""

import os
import json
import requests
from typing import Dict, List, Any, Optional
from datetime import datetime

from .base_adapter import BaseBlockchainAdapter
from utils.logger import get_logger
from utils.exceptions import AdapterException, ChainException
from middleware.unified_abstraction import (
    AccountInfo, BlockInfo, TransactionInfo, ContractInfo, ChainInfo
)

logger = get_logger(__name__)

class ThanosAdapter(BaseBlockchainAdapter):
    """Thanos Chain区块链适配器"""
    
    def __init__(self, config: Dict[str, Any] = None):
        """初始化Thanos适配器"""
        if config is None:
            config = self._load_config_from_env()
        
        super().__init__(config)
      
        # 构建基础URL
        if hasattr(self, 'api_url') and self.api_url:
            self.base_url = self.api_url.rstrip('/')
        elif hasattr(self, 'api_host') and hasattr(self, 'api_port'):
            self.base_url = f"http://{self.api_host}:{self.api_port}"
        else:
            self.base_url = "http://192.168.1.57:8581"
        
        # 请求配置
        self.session = requests.Session()
        self.session.headers.update({
            'Content-Type': 'application/json',
            'Accept': 'application/json'
        })
        
        # 存储相关配置
        self.contract_address = None
        
        logger.info(f"Initialized Thanos adapter with base URL: {self.base_url}")
    
    def _load_config_from_env(self) -> Dict[str, Any]:
        """从环境变量加载配置"""
        api_url = os.environ.get('THANOS_API_URL', 'http://192.168.1.57:8581')
        
        # 解析API URL获取host和port
        if '://' in api_url:
            protocol, rest = api_url.split('://', 1)
            if ':' in rest:
                host, port = rest.split(':', 1)
                port = port.split('/')[0]  # 移除路径部分
            else:
                host = rest.split('/')[0]
                port = '80' if protocol == 'http' else '443'
        else:
            host = '192.168.1.57'
            port = '8581'
        
        return {
            'chain_id': 'thanos',
            'node_url': api_url,
            'timeout': 30
        }
    
    async def connect(self) -> bool:
        """测试与Thanos API服务的网络连接"""
        try:
            # 直接使用API端点测试连接
            status_response = self._make_request('GET', '/api/storage/status')
            
            if status_response.get('success', False) or 'status' in status_response:
                self._connected = True
                logger.info(f"Successfully connected to Thanos API service at {self.base_url}")
                
                # 获取合约地址
                if status_response.get('contractAddress'):
                    self.contract_address = status_response.get('contractAddress')
                    logger.info(f"Contract address: {self.contract_address}")
                
                return True
            else:
                self._connected = False
                logger.error(f"Failed to connect to Thanos API service. Response: {status_response}")
                return False
                
        except Exception as e:
            self._connected = False
            logger.error(f"Connection test failed: {str(e)}")
            # 不抛出异常，只返回False
            return False
    
    async def disconnect(self) -> bool:
        """断开连接"""
        try:
            if self.session:
                self.session.close()
            self._connected = False
            logger.info("Disconnected from Thanos API service")
            return True
        except Exception as e:
            logger.error(f"Error during disconnect: {str(e)}")
            return False
    
    async def is_connected(self) -> bool:
        """检查连接状态"""
        if not self._connected:
            return False
        
        try:
            # 通过API端点验证连接
            status_response = self._make_request('GET', '/api/storage/status')
            return status_response.get('success', False) or 'status' in status_response
        except Exception:
            self._connected = False
            return False
    
    def _make_request(self, method: str, endpoint: str, data: Dict = None) -> Dict[str, Any]:
        """发送HTTP请求的通用方法"""
        url = f"{self.base_url}{endpoint}"
        try:
            if method.upper() == 'GET':
                response = self.session.get(url, timeout=self.timeout)
            elif method.upper() == 'POST':
                response = self.session.post(url, json=data, timeout=self.timeout)
            else:
                raise ValueError(f"不支持的HTTP方法: {method}")
            
            if response.headers.get('content-type', '').startswith('application/json'):
                return response.json()
            else:
                return {"text": response.text, "status_code": response.status_code}
                
        except requests.exceptions.RequestException as e:
            logger.error(f"Request failed: {str(e)}")
            raise AdapterException(f"Request failed: {str(e)}")
        except json.JSONDecodeError as e:
            logger.error(f"JSON decode failed: {str(e)}")
            raise AdapterException(f"JSON decode failed: {str(e)}")
    
    async def get_chain_info(self) -> ChainInfo:
        """获取链信息"""
        try:
            # 获取服务状态
            status_response = self._make_request('GET', '/api/storage/status')
            
            # 获取最新区块高度
            latest_block_response = self._make_request('GET', '/api/blockchain/latest-executed-number')
            
            # 获取共识轮次
            consensus_response = self._make_request('GET', '/api/blockchain/current-commit-round')
            
            return ChainInfo(
                chain_id=self.chain_id,
                chain_name="Thanos Chain",
                latest_block=latest_block_response.get('blockNumber', 0),
                network_id="thanos-network",
                consensus="Thanos Consensus",
                version="1.0.0"
            )
        except Exception as e:
            logger.error(f"Failed to get chain info: {str(e)}")
            raise AdapterException(f"Failed to get chain info: {str(e)}")
    
    def get_chain_info_sync(self) -> ChainInfo:
        """获取链信息（同步版本）"""
        try:
            # 获取服务状态
            status_response = self._make_request('GET', '/api/storage/status')
            
            # 获取最新区块高度
            latest_block_response = self._make_request('GET', '/api/blockchain/latest-executed-number')
            
            # 获取共识轮次
            consensus_response = self._make_request('GET', '/api/blockchain/current-commit-round')
            
            return ChainInfo(
                chain_id=self.chain_id,
                chain_name="Thanos Chain",
                latest_block=latest_block_response.get('blockNumber', 0),
                network_id="thanos-network",
                consensus="Thanos Consensus",
                version="1.0.0"
            )
        except Exception as e:
            logger.error(f"Failed to get chain info: {str(e)}")
            raise AdapterException(f"Failed to get chain info: {str(e)}")
    
    async def create_account(self, **kwargs) -> AccountInfo:
        """创建账户 - Thanos暂不支持通过API创建账户"""
        raise AdapterException("Account creation not supported by Thanos API")
    
    async def get_account_info(self, address: str) -> AccountInfo:
        """获取账户信息 - Thanos暂不支持"""
        raise AdapterException("Account info not supported by Thanos API")
    
    async def get_balance(self, address: str, token_address: str = None) -> float:
        """获取账户余额 - Thanos暂不支持"""
        raise AdapterException("Balance query not supported by Thanos API")
    
    async def send_transaction(self, transaction: Dict[str, Any]) -> str:
        """发送交易"""
        try:
            raw_data = transaction.get('rawData')
            if not raw_data:
                raise AdapterException("Missing rawData in transaction")
            
            response = self._make_request('POST', '/api/blockchain/send-raw-transaction', {
                'rawData': raw_data
            })
            
            if response.get('success'):
                return response.get('transactionHash', '')
            else:
                raise AdapterException(f"Transaction failed: {response.get('error', 'Unknown error')}")
                
        except Exception as e:
            logger.error(f"Failed to send transaction: {str(e)}")
            raise AdapterException(f"Failed to send transaction: {str(e)}")
    
    async def get_transaction(self, tx_hash: str) -> TransactionInfo:
        """获取交易信息"""
        try:
            # 先尝试从网关缓存获取
            response = self._make_request('GET', f'/api/blockchain/transaction/{tx_hash}')
            
            if not response.get('success'):
                # 如果缓存中没有，尝试从全量历史获取
                response = self._make_request('GET', f'/api/blockchain/transaction-by-chain/{tx_hash}')
            
            if response.get('success'):
                return TransactionInfo(
                    tx_hash=tx_hash,
                    block_number=0,  # Thanos API暂不提供
                    block_hash="",
                    transaction_index=0,
                    from_address="",
                    to_address="",
                    value=0,
                    gas_limit=0,
                    gas_price=0,
                    gas_used=0,
                    status=1,  # 假设成功
                    timestamp=datetime.now(),
                    input_data="",
                    logs=[],
                    extra_info=response.get('transactionInfo', {})
                )
            else:
                raise AdapterException(f"Transaction not found: {tx_hash}")
                
        except Exception as e:
            logger.error(f"Failed to get transaction: {str(e)}")
            raise AdapterException(f"Failed to get transaction: {str(e)}")
    
    async def get_transaction_receipt(self, tx_hash: str) -> Dict[str, Any]:
        """获取交易回执"""
        try:
            transaction_info = await self.get_transaction(tx_hash)
            return {
                'transactionHash': tx_hash,
                'status': transaction_info.status,
                'gasUsed': transaction_info.gas_used,
                'logs': transaction_info.logs,
                'extra_info': transaction_info.extra_info
            }
        except Exception as e:
            logger.error(f"Failed to get transaction receipt: {str(e)}")
            raise AdapterException(f"Failed to get transaction receipt: {str(e)}")
    
    async def estimate_gas(self, transaction: Dict[str, Any]) -> int:
        """估算Gas费用 - Thanos暂不支持"""
        return 0  # Thanos不使用Gas概念
    
    async def get_latest_block(self) -> BlockInfo:
        """获取最新区块"""
        try:
            response = self._make_request('GET', '/api/blockchain/latest-executed-number')
            
            if response.get('success'):
                block_number = response.get('blockNumber', 0)
                return await self.get_block_by_number(block_number)
            else:
                raise AdapterException("Failed to get latest block number")
                
        except Exception as e:
            logger.error(f"Failed to get latest block: {str(e)}")
            raise AdapterException(f"Failed to get latest block: {str(e)}")
    
    async def get_block_by_number(self, block_number: int) -> BlockInfo:
        """根据区块号获取区块"""
        try:
            response = self._make_request('GET', f'/api/blockchain/block/{block_number}')
            
            if response.get('success'):
                return BlockInfo(
                    block_number=block_number,
                    block_hash="",  # Thanos API暂不提供
                    parent_hash="",
                    timestamp=datetime.now(),
                    transactions=[],
                    miner="",
                    gas_used=0,
                    gas_limit=0
                )
            else:
                raise AdapterException(f"Block not found: {block_number}")
                
        except Exception as e:
            logger.error(f"Failed to get block by number: {str(e)}")
            raise AdapterException(f"Failed to get block by number: {str(e)}")
    
    async def get_block_by_hash(self, block_hash: str) -> BlockInfo:
        """根据区块哈希获取区块 - Thanos暂不支持"""
        raise AdapterException("Get block by hash not supported by Thanos API")
    
    async def get_block(self, block_identifier) -> BlockInfo:
        """根据区块号或区块哈希获取区块"""
        try:
            # 如果是整数，直接作为区块号处理
            if isinstance(block_identifier, int):
                return await self.get_block_by_number(block_identifier)
            
            # 如果是字符串，判断是区块号还是区块哈希
            if isinstance(block_identifier, str):
                if block_identifier.startswith('0x') or len(block_identifier) >= 40:
                    # 区块哈希 - Thanos暂不支持
                    raise AdapterException("Get block by hash not supported by Thanos API")
                else:
                    # 区块号字符串
                    try:
                        block_number = int(block_identifier)
                        return await self.get_block_by_number(block_number)
                    except ValueError:
                        raise AdapterException(f"Invalid block identifier: {block_identifier}")
            
            raise AdapterException(f"Invalid block identifier type: {type(block_identifier)}")
        except Exception as e:
            logger.error(f"Failed to get block: {str(e)}")
            raise AdapterException(f"Failed to get block: {str(e)}")
    
    async def deploy_contract(self, contract_data: Dict[str, Any]) -> ContractInfo:
        """部署智能合约"""
        try:
            response = self._make_request('POST', '/api/storage/contract/deploy')
            
            if response.get('success'):
                contract_address = response.get('contractAddress', '')
                self.contract_address = contract_address
                
                return ContractInfo(
                    contract_address=contract_address,
                    contract_name="SimpleStorage",
                    abi=[],  # Thanos API暂不提供
                    bytecode="",
                    source_code="",
                    compiler_version="",
                    creation_tx_hash="",
                    creator_address="",
                    creation_timestamp=datetime.now(),
                    extra_info=response
                )
            else:
                raise AdapterException(f"Contract deployment failed: {response.get('error', 'Unknown error')}")
                
        except Exception as e:
            logger.error(f"Failed to deploy contract: {str(e)}")
            raise AdapterException(f"Failed to deploy contract: {str(e)}")
    
    async def call_contract(self, contract_address: str, method: str, 
                          params: List[Any] = None, **kwargs) -> Any:
        """调用智能合约方法"""
        try:
            if method == 'set' and params and len(params) >= 2:
                # 设置键值对
                key, value = params[0], params[1]
                response = self._make_request('POST', '/api/storage/set', {
                    'key': str(key),
                    'value': str(value)
                })
                
                if response.get('success'):
                    # 生成一个模拟的交易哈希
                    import hashlib
                    import time
                    tx_data = f"{key}_{value}_{time.time()}"
                    tx_hash = hashlib.sha256(tx_data.encode()).hexdigest()
                    
                    return {
                        'message': response.get('message', 'Success'),
                        'tx_hash': tx_hash,
                        'transaction_hash': tx_hash,
                        'txHash': tx_hash
                    }
                else:
                    raise AdapterException(f"Contract call failed: {response.get('error', 'Unknown error')}")
                    
            elif method == 'get' and params and len(params) >= 1:
                # 获取键值
                key = params[0]
                response = self._make_request('GET', f'/api/storage/get/{key}')
                
                if response.get('success'):
                    return response.get('value', '')
                else:
                    return None  # 键不存在
                    
            else:
                raise AdapterException(f"Unsupported contract method: {method}")
                
        except Exception as e:
            logger.error(f"Failed to call contract: {str(e)}")
            raise AdapterException(f"Failed to call contract: {str(e)}")
    
    async def get_contract_info(self, contract_address: str) -> ContractInfo:
        """获取智能合约信息"""
        try:
            # 通过获取服务状态来验证合约
            response = self._make_request('GET', '/api/storage/status')
            
            if response.get('success') and response.get('contractAddress') == contract_address:
                return ContractInfo(
                    contract_address=contract_address,
                    contract_name="SimpleStorage",
                    abi=[],
                    bytecode="",
                    source_code="",
                    compiler_version="",
                    creation_tx_hash="",
                    creator_address="",
                    creation_timestamp=datetime.now(),
                    extra_info=response
                )
            else:
                raise AdapterException(f"Contract not found: {contract_address}")
                
        except Exception as e:
            logger.error(f"Failed to get contract info: {str(e)}")
            raise AdapterException(f"Failed to get contract info: {str(e)}")
    
    async def subscribe_events(self, event_filter: Dict[str, Any], 
                             callback: callable) -> str:
        """订阅事件 - Thanos暂不支持"""
        raise AdapterException("Event subscription not supported by Thanos API")
    
    async def unsubscribe_events(self, subscription_id: str) -> bool:
        """取消事件订阅 - Thanos暂不支持"""
        return True
    
    async def get_logs(self, filter_params: Dict[str, Any]) -> List[Dict[str, Any]]:
        """获取事件日志 - Thanos暂不支持"""
        return []
    
    # Thanos特有的方法
    async def run_basic_storage_test(self) -> Dict[str, Any]:
        """运行基础存储测试"""
        try:
            response = self._make_request('POST', '/api/storage/test/basic')
            return response
        except Exception as e:
            logger.error(f"Failed to run basic storage test: {str(e)}")
            raise AdapterException(f"Failed to run basic storage test: {str(e)}")
    
    async def run_multi_user_storage_test(self) -> Dict[str, Any]:
        """运行多用户存储测试"""
        try:
            response = self._make_request('POST', '/api/storage/test/multi-user')
            return response
        except Exception as e:
            logger.error(f"Failed to run multi-user storage test: {str(e)}")
            raise AdapterException(f"Failed to run multi-user storage test: {str(e)}")
    
    async def run_all_storage_tests(self) -> Dict[str, Any]:
        """运行所有存储测试"""
        try:
            response = self._make_request('POST', '/api/storage/test/all')
            return response
        except Exception as e:
            logger.error(f"Failed to run all storage tests: {str(e)}")
            raise AdapterException(f"Failed to run all storage tests: {str(e)}")
    
    async def send_global_node_event(self, raw_data: str) -> str:
        """发送全局节点事件"""
        try:
            response = self._make_request('POST', '/api/blockchain/send-global-node-event', {
                'rawData': raw_data
            })
            
            if response.get('success'):
                return response.get('eventHash', '')
            else:
                raise AdapterException(f"Send global node event failed: {response.get('error', 'Unknown error')}")
                
        except Exception as e:
            logger.error(f"Failed to send global node event: {str(e)}")
            raise AdapterException(f"Failed to send global node event: {str(e)}")
    
    async def get_global_node_event(self, event_hash: str, from_chain: bool = False) -> Dict[str, Any]:
        """获取全局节点事件信息"""
        try:
            endpoint = f'/api/blockchain/global-node-event-by-chain/{event_hash}' if from_chain else f'/api/blockchain/global-node-event/{event_hash}'
            response = self._make_request('GET', endpoint)
            return response
        except Exception as e:
            logger.error(f"Failed to get global node event: {str(e)}")
            raise AdapterException(f"Failed to get global node event: {str(e)}")
    
    async def get_global_node_event_receipt(self, event_hash: str) -> Dict[str, Any]:
        """获取全局节点事件回执"""
        try:
            response = self._make_request('GET', f'/api/blockchain/global-node-event-receipt/{event_hash}')
            return response
        except Exception as e:
            logger.error(f"Failed to get global node event receipt: {str(e)}")
            raise AdapterException(f"Failed to get global node event receipt: {str(e)}")
    
    async def eth_call(self, raw_data: str) -> Dict[str, Any]:
        """发送交易请求立即执行（无需共识）"""
        try:
            response = self._make_request('POST', '/api/blockchain/eth-call', {
                'rawData': raw_data
            })
            return response
        except Exception as e:
            logger.error(f"Failed to execute eth call: {str(e)}")
            raise AdapterException(f"Failed to execute eth call: {str(e)}")
    
    async def send_batch_transactions(self, raw_data_list: List[str]) -> List[str]:
        """批量发送交易请求"""
        try:
            response = self._make_request('POST', '/api/blockchain/send-raw-transaction-list', {
                'rawDataList': raw_data_list
            })
            
            if response.get('success'):
                return response.get('transactionHashList', [])
            else:
                raise AdapterException(f"Batch transaction failed: {response.get('error', 'Unknown error')}")
                
        except Exception as e:
            logger.error(f"Failed to send batch transactions: {str(e)}")
            raise AdapterException(f"Failed to send batch transactions: {str(e)}")
    
    async def get_batch_transactions(self, tx_hash_list: List[str]) -> Dict[str, Any]:
        """批量获取交易信息"""
        try:
            response = self._make_request('POST', '/api/blockchain/transactions-by-hashes', {
                'transactionHashList': tx_hash_list
            })
            return response
        except Exception as e:
            logger.error(f"Failed to get batch transactions: {str(e)}")
            raise AdapterException(f"Failed to get batch transactions: {str(e)}")